<!--
@license
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<link rel="import" href="../case-map.html">
<script>

  Polymer.Base.extend(Polymer.Bind, {

    _shouldAddListener: function(effect) {
      return effect.name &&
             effect.mode === '{' &&
             !effect.negate &&
             effect.kind != 'attribute'
             ;
    },

    _annotationEffect: function(source, value, effect) {
      if (source != effect.value) {
        value = this.get(effect.value);
        this.__data__[effect.value] = value;
      }
      var calc = effect.negate ? !value : value;
      // For better interop, dirty check before setting when custom events
      // are used, since the target element may not dirty check (e.g. <input>)
      if (!effect.customEvent ||
          this._nodes[effect.index][effect.name] !== calc) {
        return this._applyEffectValue(calc, effect);
      }
    },

    _reflectEffect: function(source) {
      this.reflectPropertyToAttribute(source);
    },

    _notifyEffect: function(source) {
      this._notifyChange(source);
    },

    // Raw effect for extension
    _functionEffect: function(source, value, fn, old) {
      fn.call(this, source, value, old);
    },

    _observerEffect: function(source, value, effect, old) {
      var fn = this[effect.method];
      if (fn) {
        fn.call(this, value, old);
      } else {
        this._warn(this._logf('_observerEffect', 'observer method `' +
          effect.method + '` not defined'));
      }
    },

    _complexObserverEffect: function(source, value, effect) {
      var fn = this[effect.method];
      if (fn) {
        var args = Polymer.Bind._marshalArgs(this.__data__, effect, source, value);
        if (args) {
          fn.apply(this, args);
        }
      } else {
        this._warn(this._logf('_complexObserverEffect', 'observer method `' +
          effect.method + '` not defined'));
      }
    },

    _computeEffect: function(source, value, effect) {
      var args = Polymer.Bind._marshalArgs(this.__data__, effect, source, value);
      if (args) {
        var fn = this[effect.method];
        if (fn) {
          this[effect.property] = fn.apply(this, args);
        } else {
          this._warn(this._logf('_computeEffect', 'compute method `' +
            effect.method + '` not defined'));
        }
      }
    },

    _annotatedComputationEffect: function(source, value, effect) {
      var computedHost = this._rootDataHost || this;
      var fn = computedHost[effect.method];
      if (fn) {
        var args = Polymer.Bind._marshalArgs(this.__data__, effect, source, value);
        if (args) {
          var computedvalue = fn.apply(computedHost, args);
          if (effect.negate) {
            computedvalue = !computedvalue;
          }
          this._applyEffectValue(computedvalue, effect);
        }
      } else {
        computedHost._warn(computedHost._logf('_annotatedComputationEffect',
          'compute method `' + effect.method + '` not defined'));
      }
    },

    // path & value are used to fill in wildcard descriptor when effect is
    // being called as a result of a path notification
    _marshalArgs: function(model, effect, path, value) {
      var values = [];
      var args = effect.args;
      for (var i=0, l=args.length; i<l; i++) {
        var arg = args[i];
        var name = arg.name;
        var v;
        if (arg.literal) {
          v = arg.value;
        } else if (arg.structured) {
          v = Polymer.Base.get(name, model);
        } else {
          v = model[name];
        }
        if (args.length > 1 && v === undefined) {
          return;
        }
        if (arg.wildcard) {
          // Only send the actual path changed info if the change that
          // caused the observer to run matched the wildcard
          var baseChanged = (name.indexOf(path + '.') === 0);
          var matches = (effect.trigger.name.indexOf(name) === 0 && !baseChanged);
          values[i] = {
            path: matches ? path : name,
            value: matches ? value : v,
            base: v
          };
        } else {
          values[i] = v;
        }
      }
      return values;
    }

  });

</script>
